package cn.spdb.harrier.server.master.stream;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import cn.spdb.harrier.common.model.JobSignal;
import cn.spdb.harrier.common.utils.DateUtils;
import cn.spdb.harrier.common.utils.FileUtils;
import cn.spdb.harrier.common.utils.Symbol;
import cn.spdb.harrier.dao.utils.BeanContext;
import cn.spdb.harrier.server.master.MasterManagerService;

@Component
public class SignalManager implements Runnable {

	/**
	 * 文件加载
	 */
	private Hashtable<String, Long> stableCheckSize = new Hashtable<String, Long>();

	private final AtomicBoolean STOP = new AtomicBoolean(false);

	@Value("${harrier.signal.receiver.path:}")
	private String RECEIVER_DIR_PATH;

	@Value("${harrier.signal.filename.matche:^dir.[0-9]+@[0-9A-Z_]+[0-9]{8,}$}")
	private String RECEIVER_SINGNAL_MATCHE;
	
	/**
	 * 静态方法 检查控制文件大小稳定后接受
	 * 
	 * @param fileName
	 * @return
	 */
	private boolean isSizeStable(File file) {
		String filePath = file.getPath();
		long len = file.length();
		Long oldLen = stableCheckSize.get(filePath);
		if (oldLen == null) {
			stableCheckSize.put(filePath, len);
			return false;
		}
		if (oldLen < len) {
			stableCheckSize.put(filePath, len);
			return false;
		}
		stableCheckSize.remove(filePath);
		return true;
	}


/**
 * 检查指定文件是否是一个合法的任务信号文件。
 *
 * <p>该方法主要完成以下判断：
 * <ul>
 *   <li>文件是否存在且为普通文件</li>
 *   <li>文件内容是否稳定（大小不再变化）</li>
 *   <li>文件名是否符合预定义的命名规则</li>
 *   <li>文件名中是否包含有效的执行日期</li>
 * </ul>
 *
 * <h3>文件命名规范示例：</h3>
 * <pre>
 *     dir.1@JOB_NAME20250405
 * </pre>
 * <ul>
 *   <li>{@code dir.1} 表示目录和批次号</li>
 *   <li>{@code JOB_NAME} 表示任务信号名称</li>
 *   <li>{@code 20250405} 表示执行日期，格式必须为 yyyyMMdd</li>
 * </ul>
 *
 * @param file 要检查的文件对象
 * @return 如果是合法的信号文件返回 true，否则返回 false
 */
public boolean checkSignalFile(File file) {
    // 确保文件存在、是普通文件，并且其大小已稳定（即写入完成）
    if (file.exists() && file.isFile() && isSizeStable(file)) {
        String fileName = file.getName();

        // 使用正则表达式校验文件名格式
        if (fileName.matches(RECEIVER_SINGNAL_MATCHE)) {
            // 提取文件名中的日期部分（最后8个字符）
            String strDate = fileName.substring(fileName.length() - 8);

            // 校验提取出的日期字符串是否符合 "yyyyMMdd" 格式
            if (DateUtils.isDate(strDate, DateUtils.PATTERN_YYYYMMDD_CONS)) {
                return true; // 所有条件满足，是合法信号文件
            }
        }
    }
    return false; // 不符合要求的文件返回 false
}


/**
 * 从信号文件中解析出任务信号对象 JobSignal。
 *
 * <p>该方法根据文件名解析出批次号(batch)、执行日期(jobDate)和任务信号(signal)，
 * 并读取文件内容获取环境变量(envs)和参数(params)，构建并返回一个完整的 JobSignal 对象。
 *
 * <h3>文件命名规范示例：</h3>
 * <pre>
 *     dir.1@JOB_NAME20250405
 * </pre>
 * <ul>
 *   <li>dir.1 表示目录和批次号</li>
 *   <li>JOB_NAME 表示任务信号</li>
 *   <li>20250405 表示执行日期，格式为 yyyyMMdd</li>
 * </ul>
 *
 * @param file 信号文件对象
 * @return 构建好的 JobSignal 任务信号对象
 */
public JobSignal createSignalFileBean(File file) {
    // 获取文件名
    String fileName = file.getName();

    // 使用 "@" 分割文件名
    String[] tmp = fileName.split(Symbol.AT);

    // 从文件名中提取 signal（任务标识）
    String signal = tmp[1].substring(0, tmp[1].length() - 8);

    // 提取 jobDate（执行日期），固定长度为 8 位数字格式：yyyyMMdd
    String jobDate = tmp[1].substring(tmp[1].length() - 8);

    // 提取 batch（批次号），文件名前缀部分如 "dir.1" → 批次号为 1
    String[] batchStr = tmp[0].split(Symbol.DIAN); // 以 "." 分割
    int batch = Integer.valueOf(batchStr[1]); // 取出批次号

    // 创建 JobSignal 对象并设置基础字段
    JobSignal jobSignal = new JobSignal();
    jobSignal.setBatch(batch);       // 设置批次号
    jobSignal.setJobDate(jobDate);   // 设置执行日期
    jobSignal.setSignal(signal);     // 设置任务信号名称
    jobSignal.setEnvs(null);         // 初始化 envs 为空
    jobSignal.setParams(null);       // 初始化 params 为空

    try {
        // 读取文件内容字符串
        String jobStr = FileUtils.readFileToString(file);

        if (!StringUtils.isEmpty(jobStr)) {
            // 将文件内容转为 JSON 对象
            JSONObject jsonObject = JSON.parseObject(jobStr);

            // 解析 "params" 字段作为参数 Map
            HashMap<String, String> params = jsonObject.getObject("params", HashMap.class);
            if (!ObjectUtils.isEmpty(params)) {
                jobSignal.setParams(params); // 设置参数
            }

            // 解析 "envs" 字段作为环境变量 Map
            HashMap<String, String> envs = jsonObject.getObject("envs", HashMap.class);
            if (!ObjectUtils.isEmpty(envs)) {
                jobSignal.setEnvs(envs); // 设置环境变量
            }
        }
    } catch (IOException e) {
        // 捕获文件读取异常，并打印堆栈信息
        e.printStackTrace();
    }

    // 返回构建完成的 JobSignal 对象
    return jobSignal;
}


	public void start() {
		STOP.set(false);
	}

	public void stop() {
		STOP.set(true);
	}

	@Override
	public void run() {
		if (STOP.get()||StringUtils.isEmpty(RECEIVER_DIR_PATH)) {
			return;
		}
		File dirFile = new File(RECEIVER_DIR_PATH);
		File[] files = dirFile.listFiles();
		for (File file : files) {
			if (checkSignalFile(file)) {
				JobSignal jobSignal = createSignalFileBean(file);
				BeanContext.getBean(MasterManagerService.class).streamJobSignal(jobSignal);
			}
		}

	}
}
